﻿import System.Exception
import sys

import clr
clr_cached_refs = set()
clr_add_ref_original = clr.AddReferenceByPartialName
def clr_add_ref_if_new(name):
  if name not in clr_cached_refs:
    clr_add_ref_original(name)
    clr_cached_refs.add(name)
clr.AddReferenceByPartialName = clr_add_ref_if_new

from System.IO import File
from System.Reflection import Assembly
#clr.AddReferenceByPartialName('WebPythonHost')
clr.AddReference(Assembly.GetEntryAssembly())
from WebPythonHost import ApplicationHlp

def write_to_log(x):
  from System.Diagnostics import Trace
  Trace.WriteLine(x)
  Trace.Flush()
def to_html(s):
  norm_s = norm_newlines(s)
  from cgi import escape
  return escape(s).replace('\n', '<br/>\n')
def html_encode(s):
  from cgi import escape
  return escape(s)
def norm_newlines(s):
  return s.replace('\r\n', '\n').replace('\r', '\n')
def to_yaml(kpiece):
  import yaml
  def represent_str(Dumper, data):
    style = '|' if ((type(data) is unicode and u'\n' in data) or (type(data) is str and '\n' in data)) else None
    return Dumper.represent_scalar(u'tag:yaml.org,2002:str', data, style=style)
  yaml.add_representer(str, represent_str)
  yaml.add_representer(unicode, represent_str)
  yaml.add_multi_representer(object, lambda dumper, data: dumper.represent_scalar(u'!obj', repr(data)))
  return yaml.dump(kpiece, default_style = None,
    default_flow_style=False, allow_unicode=True, encoding='utf-8')
def load_from_inet(url, file_name):
  from System import Uri
  from System.Net import WebClient
  from System.Threading import Monitor
  webClient = WebClient()
  monitor = Object()
  is_downloaded = False
  temp_file_name = file_name + '.dnld'
  def on_downloaded(sender, e):
    from System.IO import File
    local_is_downloaded = e.Error is None and not e.Cancelled
    if local_is_downloaded and not File.Exists(file_name):
      File.Move(temp_file_name, file_name)
    Monitor.Enter(monitor)
    try:
      is_downloaded = local_is_downloaded
      Monitor.Pulse(monitor)
    finally:
      Monitor.Exit(monitor)
  webClient.DownloadFileCompleted += on_downloaded
  webClient.DownloadFileAsync(Uri(url), temp_file_name)
  Monitor.Enter(monitor)
  try:
    return is_downloaded or (Monitor.Wait(monitor, TimeSpan.FromSeconds(10)) and is_downloaded)
  finally:
    Monitor.Exit(monitor)


try:
  import yaml
  global knowledge
  #knowledge_yaml_inet = load_from_inet('http://unnamed-site.appspot.com/kengine/execute?action=get+latest+knowledge+for+course+tracker&raw=1')['filtered_knowledge']
  #if knowledge_yaml_inet:
  #  knowledge_yaml = knowledge_yaml_inet
  knowledge = yaml.load(knowledge_yaml)
except Exception, exc:
  try:
    import traceback
  except Exception, exc2:
    raise Exception('Failed to get traceback for "%s", because "%s" happened' % (str(exc), str(exc2)))
  else:
    raise Exception(traceback.format_exc())

def knowledge_get(alias):
  return knowledge.get(alias, None)

def knowledge_get_or_literal(alias):
  return knowledge.get(alias, alias)

def execute_exec_steps_of_knowledge_piece(knowledge_piece_alias, parameters, globs):
  knowledge_piece = knowledge_get(knowledge_piece_alias)
  steps = knowledge_piece['STEPS']
  for step in steps:
    code = step['EXEC']
    if code is not None:
      exec code in globs, parameters
  return parameters

class KnowledgeException(Exception):
  def __init__(self, aliases, tb):
    self.aliases = aliases
    self.tb = tb
  def __str__(self):
    return '\n'.join(['KnowledgeException:'] + self.aliases + [self.tb])

def execute_knowledge_piece_old(knowledge_piece_alias, parameters):
  knowledge_piece_alias2 = 'execute knowledge piece'
  parameters2 = {
    'knowledge': knowledge,
    'knowledge_piece_alias': knowledge_piece_alias,
    'knowledge_piece_parameters': parameters,
  }
  globs = {
    'execute_knowledge_piece': execute_knowledge_piece,
    'knowledge_get': knowledge_get,
    'is_debug': False,
    'write_to_log': write_to_log,
    'to_html': to_html,
    'to_yaml': to_yaml,
    'html_encode': html_encode,
  }
  try:
    return execute_exec_steps_of_knowledge_piece(knowledge_piece_alias2, parameters2, globs)['results']
  except KnowledgeException, exc:
    raise KnowledgeException([knowledge_piece_alias] + exc.aliases, exc.tb)
  except:
    import traceback
    raise KnowledgeException([knowledge_piece_alias], traceback.format_exc())
  #except:
    #exc_info = sys.exc_info()
    #exc = exc_info[1]
    #tb = exc_info[2]
    #import traceback
    #raise Know
    #new_exc = Exception(knowledge_piece_alias, (exc, traceback.format_exc()))
    #write_to_log(repr(new_exc))
    #raise Exception, new_exc
    #raise System.Exception, System.Exception("Could not execute '%s'" % knowledge_piece_alias, exc if exc is System.Exception else System.Exception(str(exc))), tb

try:
  test_knowledge = yaml.load(test_knowledge_yaml)
  if test_knowledge is not None:
    knowledge.update(test_knowledge)
  #write_to_log(repr(test_knowledge))

  execute_knowledge_piece = execute_knowledge_piece_old

  compiled_knowledge_path = ApplicationHlp.MapPath('knowledge/compiled_knowledge.py')
  #compiled_knowledge = load_yaml_from('http://unnamed-site.appspot.com/kengine/execute?action=compile+latest+course+tracker+knowledge+to+python&raw=1')['python_code']
  #write_to_log(to_html(compiled_knowledge))
  compiled_knowledge = File.ReadAllText(compiled_knowledge_path)
  compiled_knowledge = norm_newlines(compiled_knowledge)
  #compiled_knowledge = execute_knowledge_piece_old('compile knowledge to python', {'knowledge': knowledge})['python_code']
  #File.WriteAllText(compiled_knowledge_path, compiled_knowledge.replace('\n', '\r\n'))

  global compiled_knowledge_module
  compiled_knowledge_module = {}

  def execute_compiled_knowledge_piece(knowledge_piece_alias, parameters):
    parameters = parameters if parameters is not None else {}
    func = compiled_knowledge_module['names'].get(knowledge_piece_alias)
    if func is not None and (type(test_knowledge) is not dict or knowledge_piece_alias not in test_knowledge):
      return func(parameters)
    else:
      return execute_knowledge_piece_old(knowledge_piece_alias, parameters)

  global execute_knowledge_piece
  execute_knowledge_piece = execute_compiled_knowledge_piece

  globs = {
    'execute_knowledge_piece': execute_compiled_knowledge_piece,
    'knowledge_get': knowledge_get,
    'knowledge_get_or_literal': knowledge_get_or_literal,
    'is_debug': False,
    'write_to_log': write_to_log,
    'to_yaml': to_yaml,
    'to_html': to_html,
    'html_encode': html_encode,
  }
  exec compiled_knowledge in globs, compiled_knowledge_module
except Exception, exc:
  try:
    import traceback
  except Exception, exc2:
    raise Exception('Failed to get traceback for "%s", because "%s" happened' % (str(exc), str(exc2)))
  else:
    raise Exception(traceback.format_exc())

def execute_knowledge_piece_wrapper(knowledge_piece_alias, parameters):
  try:
    return execute_knowledge_piece(knowledge_piece_alias, parameters)
  except Exception, exc:
    try:
      import traceback
    except Exception, exc2:
      write_to_log(to_html('Failed to get traceback for "%s", because "%s" happened' % (str(exc), str(exc2))))
    else:
      write_to_log(to_html(traceback.format_exc()))
    raise

  
